package com.e0box.game.sound
{
	
	
	import com.e0box.game.event.SoundEvent;
	import com.e0box.game.logicGraphics.Options;
	
	import utils.ObjectArray;
	
	
	public class SoundManager
	{
		/**
		 * list of hash key-SubSfx
		 */		
		private var _list:ObjectArray;
		/**
		 * play list when method playList or loopList be called
		 */		
		private var _playList:Vector.<String>;
		/**
		 * hold the list if looping
		 */		
		private var _tmpList:Vector.<String>;
		/**
		 * volume of list playing
		 */		
		private var _listVol:Number;
		/**
		 * pan of list playing
		 */		
		private var _listPan:Number;
		/**
		 * if list playing in shuffle
		 */		
		private var _listShuffle:Boolean;
		/**
		 * if loopList
		 */		
		private var _listLooping:Boolean;
		/**
		 * current SubSfx which playing
		 */		
		private var _listSfx:SubSfx;
		
		private var _isMute:Boolean = false;;
		
		private var _bgMusic:SubSfx;
		
		private static var _instance:SoundManager;
		
		
		/**
		 * until now,can't play same sound as same time.
		 * new play()/loop() will override the last play()/loop()
		 * 
		 * @param single
		 * 
		 */		
		public function SoundManager(single:validate)
		{
			if(!single){
				throw new Error("Please use the static method 'get instance'.");
			}
			init();
		}
		private function init():void{
			_list = new ObjectArray();
		}	
		/**
		 * put an soundClass in hash
		 * @param key
		 * @param soundClass
		 * 
		 */		
		public function put(key:String,soundClass:Class):void{
			var s:SubSfx = new SubSfx(soundClass);
			s.key = key;
			return _list.put(key,s);
		}
		/**
		 * check if list contains the key
		 * @param key
		 * @return 
		 * 
		 */		
		public function containsKey(key:String):Boolean{
			return _list.containsKey(key);
		}
		/**
		 * get SubSfx instance by key
		 * @param key
		 * @return 
		 * 
		 */		
		public function getSoundByKey(key:String):SubSfx{
			return _list.getValueByKey(key) as SubSfx;
		}
		/**
		 * play SubSfx instance by key
		 * @param key
		 * @param volume
		 * @param pan
		 * 
		 */		
		public function play(key:String,volume:Number = 1, startTime:Number = 0,pan:Number = 0,overlay:Boolean = true):void{
			if(_isMute) return;
			if(!containsKey(key)) return;
			if(getSoundByKey(key).playing && !overlay){
				var sfx:SubSfx = new SubSfx(getSoundByKey(key).soundClass);
				sfx.play(volume,pan,startTime);
			}else{
				getSoundByKey(key).play(volume,pan,startTime);
			}
		}
		/**
		 * loop SubSfx instance by key
		 * @param key
		 * @param loopCount
		 * @param volume
		 * @param pan
		 * 
		 */		
		public function loop(key:String,loopCount:uint = 0,volume:Number = 1,pan:Number = 0 ,overlay:Boolean = false):void{
			if(_isMute) return;
			if(!containsKey(key)) return;
			if(getSoundByKey(key).playing && !overlay){
				var sfx:SubSfx = new SubSfx(getSoundByKey(key).soundClass);
				sfx.loopIn(loopCount,volume,pan);
			}else{
				getSoundByKey(key).loopIn(loopCount,volume,pan);
			}
		}
		/**
		 * check if the SubSfx is playing which subsfx.key equal key
		 * @param key
		 * @return 
		 * 
		 */		
		public function checkPlaying(key:String):Boolean{
			if(!containsKey(key)) return false;
			return getSoundByKey(key).playing;
		}
		/**
		 * play a list 
		 * @param list
		 * @param shuffle
		 * @param volume
		 * @param pan
		 * 
		 */		
		public function playList(list:Vector.<String>,shuffle:Boolean = false,volume:Number = 1,pan:Number = 0):void{
			_listLooping = false;
			_listShuffle = shuffle;
			_listVol = volume;
			_listPan = pan;
			list = list.concat();
			var len:uint = list.length;
			
			while(len){
				if(!containsKey(list[len - 1])){
					list.splice(len - 1,1);
				}
				len--;
			}
			_playList = list;
			_tmpList = _playList.concat();
			if(_playList.length){
				/*if(_listShuffle){
					Tools.shuffleArray(Array(_playList));
				}*/
				playNext();
			}
		}
		
		/**
		 * loop a list
		 * @param list
		 * @param shuffle
		 * @param volume
		 * @param pan
		 * 
		 */		
		public function loopList(list:Vector.<String>,shuffle:Boolean = false,volume:Number = 1,pan:Number = 0):void{
			playList(list,shuffle,volume,pan);
			_listLooping = true;
		}
		
		
		/**
		 * kill the play list
		 * @param stopSound
		 * 
		 */		
		public function killList(stopSound:Boolean = true):void{
			while(_playList.length){
				_playList.pop();
			}
			while(_tmpList.length){
				_tmpList.pop();
			}
			
			if(stopSound && _listSfx){
				_listSfx.removeEventListener(SoundEvent.ON_PLAY_COMPLETE,onPlayComplete);
				_listSfx.stop();
			}
		}
		/**
		 * return all playing SubSfx instance's key
		 * @return 
		 * 
		 */		
		public function getPlaying():Vector.<String>{
			var arr:Array = _list.getKeys();
			var result:Vector.<String> = new Vector.<String>();
			for(var i:String in arr){
				if(checkPlaying(arr[i])){
					result.push(arr[i]);
				}
			}
			return result;
		}
		/**
		 * stop all of sounds
		 * 
		 */		
		private function stopAllSounds():void{
			var arr:Array = _list.getValues();
			for(var i:String in arr){
				if((arr[i] as SubSfx).playing){
					(arr[i] as SubSfx).stop();
				}
			}
			
			//_isMute = true;
		}
		
		/**
		 * resume a SubSfx instance by key
		 * @param key
		 * 
		 */		
		public function resumeByKey(key:String):void{
			if(!containsKey(key)) return;
			if(!getSoundByKey(key).playing && getSoundByKey(key).position){
				getSoundByKey(key).resume();
			}
		}
		/**
		 * clear the list hash map
		 * 
		 */		
		private function resumeAllSounds():void{
			var arr:Array = _list.getValues();
			for(var i:String in arr){
				if(!(arr[i] as SubSfx).playing && (arr[i] as SubSfx).position){
					(arr[i] as SubSfx).resume();
				}
			}
			
			//_isMute = false;
		}
		
		public function changeBgMusic(key:String,volume:Number):void{
			if(_bgMusic){
				if(_bgMusic.key == key){
					return;
				}else{
					_bgMusic.stop();
				}
			}
			
			_bgMusic = getSoundByKey(key);
			_bgMusic.loop(volume,0,100);
			
			if(_isMute) _bgMusic.stop();
			
			//loop(key,0,volume);
		}
		
		public function mute():void{
			_isMute = true;
			//stopAllSounds();
			if(_bgMusic && _bgMusic.playing) _bgMusic.stop();
		}
		public function loud():void{
			//_bgMusic
			_isMute = false;
			//resumeAllSounds();
			if(_bgMusic && !_bgMusic.playing && _bgMusic.position) _bgMusic.resume();
		}
		
		/**
		 * method of array filter
		 * @param obj
		 * @return 
		 * 
		 */		
		private function isPlaying(obj:SubSfx):Boolean{
			return obj.playing;
		}
		
		protected function playNext():void{
			if(_listLooping){
				if(!_playList.length){
					_playList = _tmpList.concat();
					
					/*if(_listShuffle){
						Tools.shuffleArray(Array(_playList));
					}*/
				}
			}
			if(_playList.length){
				var tmp:SubSfx = _listSfx;
				_listSfx = getSoundByKey(_playList.shift());
				_listSfx.play(_listVol,_listPan);
				_listSfx.addEventListener(SoundEvent.ON_PLAY_COMPLETE,onPlayComplete);
			}
		}
		
		protected function onPlayComplete(evt:SoundEvent):void{
			(evt.target as SubSfx).removeEventListener(SoundEvent.ON_PLAY_COMPLETE,onPlayComplete);
			playNext();
		}
		
		public static function get instance():SoundManager{
			if(!_instance){
				_instance = new SoundManager(new validate());
			}
			return _instance;
		}
	}
}
class validate{
	public function validate(){
		
	}
}